package ua.lviv.franko.femShapeFunction2D;

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

import org.jzy3d.maths.Range;
import org.jzy3d.plot3d.builder.Mapper;

import ua.lviv.franko.integration.IFunction2D;
import ua.lviv.franko.triangulation.SaveStructures.Node;
import ua.lviv.franko.visualisation.Visualise3D;

/**
 * 
 * @author mark
 */
public class FEMShapeFunction1 implements IFunction2D {
	boolean				isAactive	= true;
	boolean				isBactive	= true;
	boolean				isCactive	= true;
	protected Node		A;
	protected Node		B;
	protected Node		C;
	protected double	S2;

	private int			NodeNum;

	protected double	ai, aj, ak;
	protected double	bi, bj, bk;
	protected double	ci, cj, ck;

	public FEMShapeFunction1(Node A, Node B, Node C) {
		this.A = A;
		this.B = B;
		this.C = C;

		ai = B.x * C.y - C.x * B.y;
		aj = C.x * A.y - A.x * C.y;
		ak = A.x * B.y - B.x * A.y;

		bi = B.y - C.y;
		bj = C.y - A.y;
		bk = A.y - B.y;

		ci = C.x - B.x;
		cj = A.x - C.x;
		ck = B.x - A.x;

		double a = Math.sqrt((ck) * (ck) + (bk) * (bk)); // a-b
		double b = Math.sqrt((ci) * (ci) + (bi) * (bi));
		double c = Math.sqrt((cj) * (cj) + (bj) * (bj));
		double p = (a + b + c) / 2.0;
		S2 = Math.sqrt(p * (p - a) * (p - b) * (p - c)) * 2.0;
	}

	public double calculate(double x, double y) {
		if (!isInTr(A, B, C, x, y)) {
			return 0.0;
		}

		switch (NodeNum) {
		case 1:
			if (isAactive) {
				return Li(x, y);
			} else {
				return 0.0;
			}
		case 2:
			if (isBactive) {
				return Lj(x, y);
			} else {
				return 0.0;
			}
		case 3:
			if (isCactive) {
				return Lk(x, y);
			} else {
				return 0.0;
			}
		default:
			return 0.0;
		}
	}

	public double calculateDerivatyX(double x, double y) {
		if (!isInTr(A, B, C, x, y)) {
			return 0.0;
		}

		switch (NodeNum) {
		case 1:
			if (isAactive) {
				return bi / S2;
			}
		case 2:
			if (isBactive) {
				return bj / S2;
			}
		case 3:
			if (isCactive) {
				return bk / S2;
			}
		default:
			return 0.0;
		}
	}

	public double calculateDerivatyXI(double x, double y, int i) {
		if (!isInTr(A, B, C, x, y)) {
			return 0.0;
		}

		switch (i) {
		case 1:
			return bi / S2;
		case 2:
			return bj / S2;
		case 3:
			return bk / S2;
		default:
			return 0.0;
		}
	}

	// private double cut(double val){
	// if(val>1.0){
	// return 0.0;
	// }else {
	// return val;
	// }
	// }

	public double calculateDerivatyY(double x, double y) {
		if (!isInTr(A, B, C, x, y)) {
			return 0.0;
		}

		switch (NodeNum) {
		case 1:
			if (isAactive) {
				return ci / S2;
			}
		case 2:
			if (isBactive) {
				return cj / S2;
			}
		case 3:
			if (isCactive) {
				return ck / S2;
			}
		default:
			return 0.0;
		}
	}

	public double calculateDerivatyYI(double x, double y, int i) {
		if (!isInTr(A, B, C, x, y)) {
			return 0.0;
		}

		switch (i) {
		case 1:
			return ci / S2;
		case 2:
			return cj / S2;
		case 3:
			return ck / S2;
		default:
			return 0.0;
		}
	}

	public double calculateI(double x, double y, int i) {
		if (!isInTr(A, B, C, x, y)) {
			return 0.0;
		}

		// if()
		switch (i) {
		case 1:
			return Li(x, y);
		case 2:
			return Lj(x, y);
		case 3:
			return Lk(x, y);
		default:
			return 0.0;
		}
	}

	public IFunction2D calculateMultFuncs(final int i, final int j) {
		return new IFunction2D() {

			public double calculate(double x, double y) {
				return calculateI(x, y, i) * calculateI(x, y, j);
			}

			/**
			 * 
			 * 
			 * @return the value func i multipled by derivatyX of func j
			 */
			public double calculateDerivatyX(double x, double y) {
				return calculateI(x, y, i) * calculateDerivatyXI(x, y, j);
			}

			/**
			 * 
			 * 
			 * @return the value func i multipled by derivatyY of func j
			 */
			public double calculateDerivatyY(double x, double y) {
				return calculateI(x, y, i) * calculateDerivatyYI(x, y, j);
			}
		};

		/*
		 * if((i==1)&&(j==2)){ return new IFunction2D() {
		 * 
		 * public double calculate(double x, double y) { return Li(x, y)*Lj(x, y); }
		 * 
		 * public double calculateDerivatyX(double x, double y) { return Li(x, y)*bj/S2 + Lk(x, y)*bi/S2; }
		 * 
		 * public double calculateDerivatyY(double x, double y) { return Li(x, y)*cj/S2 + Lk(x, y)*ci/S2; } }; }else{ if((i==1)&&(j==3)){ return new IFunction2D() {
		 * 
		 * public double calculate(double x, double y) { return Li(x, y)*Lk(x, y); }
		 * 
		 * public double calculateDerivatyX(double x, double y) { return Li(x, y)*bk/S2 + Lk(x, y)*bi/S2; }
		 * 
		 * public double calculateDerivatyY(double x, double y) { return Li(x, y)*ck/S2 + Lk(x, y)*ci/S2; } }; }else{ return new IFunction2D() {
		 * 
		 * public double calculate(double x, double y) { return Lj(x, y)*Lk(x, y); }
		 * 
		 * public double calculateDerivatyX(double x, double y) { return Lk(x, y)*bj/S2 + Lj(x, y)*bk/S2; }
		 * 
		 * public double calculateDerivatyY(double x, double y) { return Lk(x, y)*cj/S2 + Lj(x, y)*ck/S2; } }; } }
		 */
	}

	public Node getA() {
		return A;
	}

	public Node getB() {
		return B;
	}

	public Node getC() {
		return C;
	}

	public void setNodeInactive(int node, boolean key) {
		switch (node) {
		case 1:
			isAactive = key;
		case 2:
			isBactive = key;
		case 3:
			isCactive = key;
		default:
			;
		}
	}

	public void setNodeNum(int NodeNum) {
		this.NodeNum = NodeNum;
		/**
		 * 1 - вузол i; 2 - вузол j; 3 - вузол k;
		 */
	}

	private double Li(double x, double y) {
		// return Math.max(0.0, (ai+bi*x+ci*y)/S2);
		return (ai + bi * x + ci * y) / S2;
	}

	private double Lj(double x, double y) {
		// return Math.max(0.0,(aj+bj*x+cj*y)/S2);
		return (aj + bj * x + cj * y) / S2;
	}

	private double Lk(double x, double y) {
		// return Math.max(0.0,(ak+bk*x+ck*y)/S2);
		return (ak + bk * x + ck * y) / S2;
	}

	boolean isInTr(Node A, Node B, Node C, double x, double y) {
		double Str = S(A.x, A.y, B.x, B.y, C.x, C.y);
		double Str1 = S(x, y, B.x, B.y, C.x, C.y);
		double Str2 = S(A.x, A.y, x, y, C.x, C.y);
		double Str3 = S(A.x, A.y, B.x, B.y, x, y);

		return Math.abs(Str - (Str1 + Str2 + Str3)) < 1E-10;
	}

	double S(double x1, double y1, double x2, double y2, double x3, double y3) {
		return Math.abs((x2 * y3 + x1 * y2 + y1 * x3 - (y2 * x3 + y1 * x2 + x1 * y3)) / 2.0);
	}

	public static void main(String[] args) {
		final FEMShapeFunction1 f = new FEMShapeFunction1(new Node(0.0, 0.0, true, 0), new Node(1.0, 0.5, true, 1), new Node(0.0, 0.5, true, 2));
		f.setNodeNum(3);
		f.calculate(0.0, 0.0);

		Visualise3D.show(new Mapper() {

			@Override
			public double f(double x, double y) {

				return f.calculate(x, y);
			}
		}, new Range(-1.5, 1.5), new Range(-1.5, 1.5));
	}

	/*
	 * public IFunction2D calculateMultFuncDeriv(int func,int der){ return new IFunction2D() {
	 * 
	 * public double calculate(double x, double y) { return calculateI(x, y, func)*calculateDerivatyX(x, y) }
	 * 
	 * public double calculateDerivatyX(double x, double y) { throw new UnsupportedOperationException("Not supported yet."); }
	 * 
	 * public double calculateDerivatyY(double x, double y) { throw new UnsupportedOperationException("Not supported yet."); } } }
	 */
}
